<script lang="ts" setup>
import { VueDraggable } from "vue-draggable-plus";
import type {
  FormDesignerModel,
  FormModel,
  FormDesignerField,
  FormDesignerComponents
} from "./FormComponentMixin";
import {
  commonComponents,
  components,
  FormItem,
  FormComponentConfigs
} from "./FormComponents";
import { computed, onMounted, ref } from "vue";
import { ElMessageBox } from "element-plus";
import FormRender from "./FormRender.vue";
import CommonDialog from "@/components/commonDialog.vue";
import FormComponent from "./component/FormComponent.vue";
import JsonEditorVue from "json-editor-vue3";
import { getLibrary } from "@/api/flow/form/";
import { getRandNodeId } from "@/utils/process";
import { formJson } from "../FormStore";
import { initFormData } from "./FormInit";
import { useMessage } from "@/hooks/message";

//保存编辑历史
//表单模型定义
const formDef = defineModel<FormDesignerModel>("formDef");
//表单
const formModel = defineModel<FormModel>("formModel");

const history = ref([]);
const showTip = ref(true);
const active = ref<FormDesignerComponents>();
const activeKey = ref(0);
const previewVisible = ref(false);
const editCodeVisible = ref(false);
const formDataVisible = ref(false);
const formValidateRuleVisible = ref(false);
const formRenderRef = ref(null);
const tabsRef = ref(null);
const currentTabs = ref("common");
const formDefEdit = ref<FormDesignerModel>(null);
const formData = ref({});
const formValidateRule = ref({});
const flowFormLibrary = ref<FormDesignerField>();
const tableStorage = ref(false);

const props = defineProps({
  fullscreen: {
    type: Boolean,
    default: false
  },
  formtype: {
    type: String,
    default: "flow"
  }
});

const tableListRefs = ref<any>({});
const componentRefs = ref<any>({});
provide("componentRefs", componentRefs);
provide("tableListRefs", tableListRefs);
provide("perm", []);

const _showTip = computed(() => {
  return showTip.value && formDef.value.components.length === 0;
});

// 初始化设置表单组件
onMounted(() => {
  formJson.value = formDef.value.components;
  initDataAndRule(formDef.value.components);
});

const initDataAndRule = async components => {
  if (components.length > 0) {
    console.log("init formData", formData.value);
    const data = initFormData(components);
    formData.value = data;
    console.log("init formData", formData.value);
  }
};

watchEffect(() => {
  if (formDef.value) {
    formJson.value = formDef.value.components;
    initDataAndRule(formDef.value.components);
  }
});

const onSourceStart = event => {};

function onSourceClone(el) {
  const clone = JSON.parse(JSON.stringify(el));
  if (!clone.code) {
    clone.code = clone.type + getRandNodeId();
  }
  clone.id = getRandNodeId();
  return clone;
}

function onFieldSourceStart(event) {}

function onFieldSourceClone(el) {
  const field = JSON.parse(JSON.stringify(el));
  const clone = FormItem[field.type].create();
  clone.id = getRandNodeId();
  clone.code = field.code;
  clone.name = field.name;
  if (field.props) {
    for (const key in field.props) {
      clone.props[key] = field.props[key];
    }
  }
  return clone;
}

function addHis(v: any) {
  history.value.push(v);
  if (history.value.length >= 50) {
    history.value.splice(0, 1);
  }
}

function onTargetChoose(event) {
  activeKey.value = event.oldIndex;
}

const onTargetAdd = event => {
  console.log("on target add", event);
  showTip.value = false;
  addHis(formDef.value.components[event.newIndex]);
};

const onTargetRemove = event => {
  showTip.value = true;
  formDef.value.components.splice(event.oldIndex, 1);
};

const onTargetMoved = event => {
  const oldIndex = event.oldIndex;
  //交换位置
  const oldElement = history.value[oldIndex];
  history.value.splice(0, 1);
  history.value.push(oldElement);
};

function onTargetComponentClick(cp) {
  active.value = cp;
}

const cancelForm = () => {
  formDef.value.components.splice(formDef.value.components.length - 1, 1);
};

const redoForm = () => {
  if (formDef.value.components.length < history.value.length) {
    formDef.value.components.push(
      history.value[formDef.value.components.length]
    );
  }
};

function clearForm() {
  ElMessageBox.confirm("您确定要清空表单设计区吗?", "提醒", {
    confirmButtonText: "我再想想",
    cancelButtonText: "确认清空",
    type: "warning"
  }).catch(err => {
    formData.value = {};
    formDef.value = {
      conf: {
        labelPosition: "right", //标签位置
        labelWidth: 80, //标签宽度，
        size: "default"
      },
      components: []
    };
    history.value = [];
    showTip.value = true;
  });
}

function previewForm() {
  previewVisible.value = true;
}

const editFormCode = () => {
  editCodeVisible.value = true;
};

function validate() {
  return new Promise<void>((resolve, reject) => {
    if (formDef.value.components.length > 0) {
      resolve();
    } else {
      reject(["表单组件为空"]);
    }
  });
}

const handleEditFormConfirm = () => {
  editCodeVisible.value = false;
  if (formDefEdit.value) {
    formDef.value = formDefEdit.value;
  }
};

const handleFormDefChange = json => {
  formDefEdit.value = json;
};

const handleValidForm = () => {
  formRenderRef.value.validateForm().then(valid => {
    if (valid) {
      useMessage().success("校验通过");
    } else {
      useMessage().error("校验失败");
    }
  });
};

const handleShowFormData = () => {
  formDataVisible.value = true;
};

const handleShowFormValidateRule = () => {
  formValidateRule.value = formRenderRef.value.getFormRule();
  formValidateRuleVisible.value = true;
};

defineExpose({ validate });
</script>

<template>
  <el-container class="form-container">
    <el-aside width="200px" class="form-designer-library">
      <el-tabs ref="tabsRef" v-model="currentTabs" stretch type="border-card">
        <el-tab-pane
          label="通用组件库"
          name="common"
          v-if="tableStorage === false"
        >
          <div
            :class="{
              'library-container': true,
              'library-container-fullscreen': props.fullscreen
            }"
          >
            <el-scrollbar
              :class="{
                'scrollbar-container': true,
                'scrollbar-container-fullscreen': props.fullscreen
              }"
            >
              <el-collapse accordion>
                <el-collapse-item
                  v-for="(group, gi) in components"
                  :key="gi"
                  accordion
                  :title="group.name"
                  class="library-group"
                >
                  <VueDraggable
                    v-model="group.components"
                    :group="{ name: 'FormDesign', pull: 'clone', put: false }"
                    :sort="false"
                    :start="onSourceStart"
                    :clone="onSourceClone"
                    class="library-group-items"
                  >
                    <div
                      v-for="formCp in group.components"
                      :key="formCp.type"
                      class="library-group-item"
                    >
                      <IconifyIconOnline :icon="formCp.icon" />
                      <span>{{ formCp.name }}</span>
                    </div>
                  </VueDraggable>
                </el-collapse-item>
              </el-collapse>
            </el-scrollbar>
          </div>
        </el-tab-pane>
      </el-tabs>
    </el-aside>
    <el-container style="flex-grow: 1">
      <el-header class="form-designer-toolbar">
        <div>
          <el-tooltip effect="dark" content="撤销" placement="top">
            <div @click="cancelForm">
              <el-icon><Back /></el-icon>
            </div>
          </el-tooltip>
          <el-tooltip effect="dark" content="重做" placement="top">
            <div @click="redoForm">
              <el-icon><Right /></el-icon>
            </div>
          </el-tooltip>
        </div>
        <div>
          <el-tooltip effect="dark" content="编辑表单" placement="top">
            <div @click="editFormCode">
              <el-icon><Edit /></el-icon>
              <span>编辑</span>
            </div>
          </el-tooltip>
          <el-tooltip effect="dark" content="清空设计" placement="top">
            <div @click="clearForm">
              <el-icon><Delete /></el-icon>
              <span>清除</span>
            </div>
          </el-tooltip>
          <el-tooltip effect="dark" content="预览表单" placement="top">
            <div @click="previewForm">
              <el-icon><View /></el-icon>
              <span>预览</span>
            </div>
          </el-tooltip>
        </div>
      </el-header>
      <el-scrollbar
        :class="{
          'scrollbar-container': true,
          'scrollbar-container-fullscreen': props.fullscreen
        }"
      >
        <el-form
          :label-width="formDef.conf.labelWidth"
          :label-position="formDef.conf.labelPosition"
          :size="formDef.conf.size"
          :class="{
            'form-designer-content': true,
            'form-designer-content-fullscreen': props.fullscreen
          }"
        >
          <VueDraggable
            v-model="formDef.components"
            :animation="150"
            ghostClass="w-f-cp-select"
            @choose="onTargetChoose"
            @add="onTargetAdd"
            group="FormDesign"
            @remove="onTargetRemove"
            @update="onTargetMoved"
            class="form-designer-content-ep"
          >
            <template v-for="(cp, i) in formDef.components" :key="cp.id">
              <el-form-item
                v-if="cp.props.isFormItem"
                :label="cp.name"
                :required="cp.props.required"
                @click="onTargetComponentClick(cp)"
                :class="{
                  'w-form-d-item': true,
                  'w-form-cp-active': active?.id === cp.id,
                  'w-form-cp-nlb': cp.props.hideLabel
                }"
              >
                <FormComponent
                  :index="i"
                  :parents="formDef.components"
                  mode="free"
                  :type="cp.type"
                  :config="cp"
                  v-model="formData[cp.code]"
                  v-model:active="active"
                />
              </el-form-item>
              <FormComponent
                v-else-if="cp.props.isSubform && cp.props.isSubform === true"
                :index="i"
                :parents="formDef.components"
                mode="free"
                :config="cp"
                :type="cp.type"
                v-model="formData[cp.code]"
                v-model:active="active"
                @click="onTargetComponentClick(cp)"
                :class="{
                  'w-form-d-item': true,
                  'w-form-cp-active': active?.id === cp.id
                }"
              />
              <FormComponent
                v-else
                :index="i"
                :parents="formDef.components"
                mode="free"
                :config="cp"
                :type="cp.type"
                v-model="formData"
                v-model:active="active"
                @click="onTargetComponentClick(cp)"
                :class="{
                  'w-form-d-item': true,
                  'w-form-cp-active': active?.id === cp.id
                }"
              />
            </template>
          </VueDraggable>
          <div class="w-form-d-tip" v-if="_showTip">
            <span>💕 请从左侧组件库拖拽表单组件到此处</span>
          </div>
        </el-form>
      </el-scrollbar>
    </el-container>
    <el-aside
      width="250px"
      :class="{
        'form-designer-conf': true,
        'form-designer-conf-fullscreen': props.fullscreen
      }"
    >
      <el-form label-width="80" size="small">
        <el-tabs stretch type="border-card">
          <el-tab-pane label="组件设置" v-if="active">
            <div style="padding: 5px">
              <el-scrollbar
                :class="{
                  'scrollbar-container': true,
                  'scrollbar-container-fullscreen': props.fullscreen
                }"
              >
                <component
                  :is="FormComponentConfigs[active.type]"
                  v-model:config="active"
                />
              </el-scrollbar>
            </div>
          </el-tab-pane>
          <el-tab-pane label="表单设置">
            <div style="padding: 5px">
              <el-form-item label="标签位置">
                <el-radio-group v-model="formDef.conf.labelPosition">
                  <el-radio-button label="上面" value="top" />
                  <el-radio-button label="靠左" value="left" />
                  <el-radio-button label="靠右" value="right" />
                </el-radio-group>
              </el-form-item>
              <el-form-item label="标签宽度">
                <el-input
                  type="number"
                  v-model="formDef.conf.labelWidth"
                ></el-input>
              </el-form-item>
              <el-form-item label="组件尺寸">
                <el-radio-group v-model="formDef.conf.size">
                  <el-radio-button label="大" value="large" />
                  <el-radio-button label="中" value="default" />
                  <el-radio-button label="小" value="small" />
                </el-radio-group>
              </el-form-item>
            </div>
          </el-tab-pane>
        </el-tabs>
      </el-form>
    </el-aside>
    <CommonDialog
      v-model="previewVisible"
      width="800"
      title="表单预览"
      :border="true"
      ok-text="表单校验"
      cancel-text="关闭"
      @ok="handleValidForm"
      @cancel="previewVisible = false"
      @closed="previewVisible = false"
    >
      <template #default>
        <FormRender
          v-model:config="formDef"
          v-model="formData"
          mode="normal"
          ref="formRenderRef"
        />
      </template>
      <template #footerbtn>
        <el-button type="info" @click="handleShowFormValidateRule">
          验证规则
        </el-button>
        <el-button type="success" @click="handleShowFormData">
          表单数据
        </el-button>
      </template>
    </CommonDialog>
    <CommonDialog
      v-model="formDataVisible"
      width="700px"
      title="表单数据"
      :border="false"
      :showFooterOk="false"
      ok-text="确认"
      cancel-text="关闭"
      @cancel="formDataVisible = false"
      @closed="formDataVisible = false"
    >
      <div class="json-container">
        <JsonEditorVue
          v-model="formData"
          language="zh-CN"
          currentMode="form"
          class="json-content"
        />
      </div>
    </CommonDialog>
    <CommonDialog
      v-model="formValidateRuleVisible"
      width="700px"
      title="验证规则"
      :border="false"
      :showFooterOk="false"
      ok-text="确认"
      cancel-text="关闭"
      @cancel="formValidateRuleVisible = false"
      @closed="formValidateRuleVisible = false"
    >
      <div class="json-container">
        <JsonEditorVue
          v-model="formValidateRule"
          language="zh-CN"
          currentMode="form"
          class="json-content"
        />
      </div>
    </CommonDialog>
    <CommonDialog
      v-model="editCodeVisible"
      width="700px"
      title="表单编辑"
      :border="false"
      ok-text="确认"
      cancel-text="关闭"
      @ok="handleEditFormConfirm"
      @cancel="editCodeVisible = false"
      @closed="editCodeVisible = false"
    >
      <div class="json-container">
        <JsonEditorVue
          v-model="formDef"
          language="zh-CN"
          currentMode="code"
          class="json-content"
          @update:modelValue="handleFormDefChange"
        />
      </div>
    </CommonDialog>
  </el-container>
</template>

<style lang="scss" scoped>
@use "/src/assets/style/form/global";

$tool-nav-height: 35px;

.form-container {
  display: flex;
  flex-direction: row;
  font-size: var(--el-font-size-base);
  color: var(--el-text-color);
  width: 100%;

  :deep(.el-tabs__header) {
    .el-tabs__nav {
      height: calc($tool-nav-height);
    }

    .el-tabs__item {
      height: calc($tool-nav-height);
      font-size: small;
    }
  }

  :deep(.el-tabs__content) {
    padding: 0px !important;
  }
}

.form-designer-library {
  width: 200px;
  border-right: 1px solid var(--el-border-color);
}

.form-designer-conf {
  width: 250px;
  height: calc(100vh - 150px);
  overflow-y: hidden;
  border-left: 1px solid var(--el-border-color);
}

.form-designer-conf-fullscreen {
  width: 250px;
  height: calc(100vh - 85px);
  overflow-y: hidden;
  border-left: 1px solid var(--el-border-color);
}

.library-container {
  font-size: small;
  height: calc(100vh - 120px);
  background-color: $main-bgc !important;

  :deep(.el-scrollbar) {
    padding: 0px 2px;
  }
}

.library-container-fullscreen {
  font-size: small;
  height: calc(100vh - 120px);
  background-color: $main-bgc !important;

  :deep(.el-scrollbar) {
    padding: 0px 3px;
  }
}

.library-group {
  .library-group-items {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    color: var(--el-text-color-primary);
    background-color: $main-bgc !important;
    padding: 5px 0px;
  }

  .library-group-item {
    display: flex;
    align-items: center;
    width: 95px;
    padding: 2px;
    color: var(--el-text-color-primary);
    background: white;
    border: 1px solid var(--el-color-primary);
    border-radius: 10px;
    padding: 3px 0;
    border-radius: 8px;
    box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.1);

    & > span {
      margin-left: 5px;
    }

    &:hover {
      color: var(--el-color-primary);
      cursor: grab;
      background-color: var(--el-color-primary-light-9);
      border-color: var(--el-color-primary);
    }
  }
}

.form-designer-toolbar {
  position: relative;
  display: flex;
  align-items: center;
  height: $tool-nav-height;
  padding: 0 20px;
  background: white;

  .w-f-d-t-active {
    color: #656363;
  }

  & > div {
    font-size: medium;
    color: #989898;
    display: flex;

    & > * {
      padding: 2px;
      margin: 0 5px;
      cursor: pointer;

      &:focus {
        outline: none;
      }

      &:hover {
        color: #656363;
      }
    }
  }

  & > div:nth-child(2) {
    margin-left: 20px;
  }

  & > div:nth-child(2) {
    position: absolute;
    right: 20px;
    display: flex;
    font-size: small;

    & > div {
      display: flex;
      align-items: center;

      span {
        margin-left: 5px;
      }
    }

    & > div:first-child {
      color: var(--el-color-danger);
    }

    & > div:last-child {
      color: var(--el-color-primary);
    }
  }
}

.scrollbar-container {
  height: calc(100vh - 175px);
}

.scrollbar-container-fullscreen {
  height: calc(100vh - 120px);
}

.form-designer-content {
  position: relative;
  min-height: calc(100vh - 160px);
  height: auto;

  padding: 5px;
  margin: 5px;
  background-color: white;
  border-radius: 5px;

  .form-designer-content-ep {
    min-height: calc(100vh - 190px);
    height: auto;
  }
}

.form-designer-content-fullscreen {
  position: relative;
  min-height: calc(100vh - 110px);
  padding: 5px;
  margin: 5px;
  background-color: white;
  border-radius: 5px;

  .form-designer-content-ep {
    min-height: calc(100vh - 125px);
  }
}

.w-form-d-tip {
  position: relative;
  display: flex;
  justify-content: center;
  padding: 20px;
  color: #8d8d8d;

  span {
    position: absolute;
    top: -45vh;
  }
}

.w-f-cp-select {
  border: 1px dashed var(--el-color-primary) !important;
  border-radius: 2px;
}

.json-container {
  width: 100%;
  height: 480px;

  .json-content {
    width: 100%;
    height: 95%;
    overflow-y: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    //隐藏全屏按钮
    ::v-deep(.full-screen) {
      display: none !important;
    }
    //隐藏powderedby
    ::v-deep(.jsoneditor-poweredBy) {
      display: none !important;
    }
  }
}
</style>
